package com.conf4j;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.conf4j.kit.StrKit;
import com.conf4j.kit.ValueKit;
import com.conf4j.scaner.ConfigScaner;
import com.conf4j.scaner.IConfigScanerLinstener;

/**
 * 配置管理类
 * 
 * @author dingnate
 *
 */
public class ConfigManager {
	private static transient final Logger LOG = LoggerFactory.getLogger(ConfigManager.class);
	private static HashMap<String, Method> key2Methods = new HashMap<String, Method>();
	private static HashMap<Class<?>, Object> configs = new HashMap<Class<?>, Object>();
	private static ConfigScaner scaner;
	private static Properties mainProperties = new Properties();

	static {
		try {
			scaner = (ConfigScaner) Class.forName(Conf4jConfigScanerConf.me.getClassName()).newInstance();
			scaner.addListener(new ConfigManagerScanerLinstener());
		} catch (Exception e) {
			LOG.error("init scaner failed!", e);
		}
	}

	/**
	 * 开启配置扫描
	 */
	public static void startScaner() {
		if (scaner != null)
			scaner.start();
	}

	/**
	 * 停止配置扫描
	 */
	public static void stopScaner() {
		if (scaner != null)
			scaner.stop();
	}

	/**
	 * 缓存propertykey到method映射
	 * 
	 * @param propertykey
	 * @param method
	 */
	public static void putMethod(String propertykey, Method method) {
		key2Methods.put(propertykey, method);
	}

	/**
	 * 添加配置对象
	 * 
	 * @param config
	 */
	public static void addConfig(Object config) {
		configs.put(config.getClass(), config);
	}

	/**
	 * 获取配置对象
	 * 
	 * @param clazz
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T config(Class<T> clazz) {
		T config = (T) configs.get(clazz);
		if (config != null)
			return config;
		T instance = null;
		try {
			// 初始化clazz
			instance = clazz.newInstance();
		} catch (Exception e) {
			return null;
		}
		config = (T) configs.get(clazz);
		if (config != null)
			return config;
		addConfig(instance);
		return instance;
	}

	/**
	 * 添加properties到mainProperties
	 * 
	 * @param properties
	 */
	public static void putProperties(Properties properties) {
		mainProperties.putAll(properties);
	}

	/**
	 * 根据配置全名获取配置字符串值
	 * 
	 * @param key
	 * @return
	 */
	public static String getValueByKey(String key) {
		String value = "";
		if (scaner != null)
			value = (String) scaner.getProps().get(key);
		if (StrKit.isNotBlank(value))
			return value;
		return mainProperties.getProperty(key, ValueKit.EMPTY);
	}

	/**
	 * ConfigManager的扫描监听器
	 * 
	 * @author dingnate
	 *
	 */
	private final static class ConfigManagerScanerLinstener implements IConfigScanerLinstener {
		public void onChange(String key, String propertyKey, String oldValue, String newValue) {
			// 变更mainProperties属性
			onChangeMainProperties(propertyKey, newValue);
			// 变更配置对象属性
			onChangeConfig(propertyKey, newValue);
		}

		/**
		 * 变更mainProperties属性
		 * 
		 * @param propertyKey
		 * @param newValue
		 */
		private void onChangeMainProperties(String propertyKey, String newValue) {
			if (newValue == null)
				mainProperties.remove(propertyKey);
			else
				mainProperties.put(propertyKey, newValue);
		}

		/**
		 * 变更配置对象属性
		 * 
		 * @param propertyKey
		 * @param newValue
		 */
		private void onChangeConfig(String propertyKey, String newValue) {
			Method method = key2Methods.get(propertyKey);
			if (method == null)
				return;
			Object object = configs.get(method.getDeclaringClass());
			if (object == null)
				return;
			try {
				method.invoke(object,
						newValue == null ? null : ValueKit.convert(newValue, method.getParameterTypes()[0]));
			} catch (Exception e) {
				LOG.error(String.format("配置类[%s]属性[%s]注入失败", object.getClass().getName(), propertyKey), e);
			}
		}
	}
}
